#include "Node.h"
#include <assert.h>

namespace GeorgeLib
{
	Node::Node(void)
		: mRot(NULL)
		, mScale(NULL)
		, tag(INVALID_TAG)
		, children(NULL)
		, parent(NULL)
		, bDraw(true)
	{
	}

	Node::~Node(void)
	{
		DELETE_PTR(mRot);
		DELETE_PTR(mScale);
	}

	bool Node::Init(void)
	{
		return true;
	}

	void Node::Draw(void)
	{
	}

	void Node::Update(float delta)
	{
	}

	void Node::DrawChildren(void)
	{
		glPushMatrix();

		if (mRot && *mRot != vec3(0, 0, 0))
		{
			glRotatef(mRot->x, 1, 0, 0);
			glRotatef(mRot->y, 0, 1, 0);
			glRotatef(mRot->z, 0, 0, 1);
		}

		if (mScale) glScalef(mScale->x, mScale->y, mScale->z);

		if (parent)
		{
			vec3 t = wPos - parent->wPos;
			glTranslatef(t.x, t.y, t.z);
		}

		if (bDraw) Draw();

		if (!children) { glPopMatrix(); return; }

		for (ListIter it = children->begin(); it != children->end(); it++)
		{
			if (*it)
			{
				(*it)->DrawChildren();
			}
		}

		glPopMatrix();
	}

	void Node::UpdateChildren(float delta)
	{
		if (!children) return;
		for (ListIter it = children->begin(); it != children->end(); it++)
		{
			if (*it)
			{
				(*it)->Update(delta);
				(*it)->UpdateChildren(delta);
			}
		}
	}

	void Node::AddChild(Node *child)
	{
		// We don't want them null pointers y'all
		ErrorMsg(!child, "Invalid child pointer");
		ErrorMsg(child->parent, "Node already has a parent");

		if (!children) children = new list < Node* > ;

		// Girl needs a little identifier
		child->SetTag(children->size());

		// Push her in em list
		children->push_back(child);

		child->wPos += wPos;

		// Babe needs to know her parents
		child->SetParent(this);
	}

	Node* Node::GetChild(int tag)
	{
		ErrorMsgReturn(tag == INVALID_TAG, "Invalid tag number", NULL);
		ErrorMsgReturn(!children, "Node has no children", NULL);

		Node* child = NULL;
		ListIter i;

		for (i = children->begin(); i != children->end(); ++i)
		{
			if (tag == (*i)->GetTag())
				child = *i;
		}

		ErrorMsgReturn(!child, "Child not found", NULL);

		return child;
	}

	list<Node*>* Node::GetChildren(void)
	{
		return children;
	}

	int Node::GetChildrenCount(void)
	{
		return (children) ? children->size() : 0;
	}

	void Node::RemoveChild(Node* child)
	{
		ErrorMsg(!child, "Invalid child pointer");
		ErrorMsg(!children, "Node has no children");

		children->remove(child);
	}

	void Node::RemoveChildbyTag(int tag)
	{
		ErrorMsg(tag == INVALID_TAG, "Invalid tag number");
		ErrorMsg(!children, "Node has no children");

		Node* child = GetChild(tag);
		RemoveChild(child);
	}

	void Node::SetParent(Node *Parent)
	{
		ErrorMsg(!Parent, "Invalid parent pointer");

		// Remove this child from the old parent's list
		if (parent) parent->RemoveChild(this);

		parent = Parent;
	}

	Node* Node::GetParent(void)
	{
		// <dadjoke> Node is Batman </dadjoke>
		ErrorMsgReturn(!parent, "Node has no parent", NULL);

		return parent;
	}

	void Node::SetTag(int Tag)
	{
		tag = Tag;
	}

	int Node::GetTag(void)
	{
		return tag;
	}

	void Node::Translate(float x, float y, float z)
	{
		wPos += vec3(x, y, z);
		if (children)
			for (ListIter i = children->begin(); i != children->end(); ++i)
				(*i)->Translate(x, y, z);
	}

	void Node::Translate(vec3 v)
	{
		Translate(v.x, v.y, v.z);
	}

	void Node::Rotate(float angle, float x, float y, float z)
	{
		if (mRot == NULL) mRot = new vec3;
		if (x) mRot->x += angle * x;
		if (y) mRot->y += angle * y;
		if (z) mRot->z += angle * z;
	}

	void Node::Rotate(float angle, vec3 v)
	{
		Rotate(angle, v.x, v.y, v.z);
	}

	void Node::Scale(float x, float y, float z)
	{
		if (mScale == NULL) mScale = new vec3(1, 1, 1);
		mScale->operator()(x, y, z);
	}

	void Node::Scale(vec3 v)
	{
		Scale(v.x, v.y, v.z);
	}

	vec3 Node::getWorldPos(void)
	{
		return wPos;
	}

	void Node::setWorldPos(vec3 v)
	{
		wPos = v;
	}

	vec3 Node::getRelativePos(void)
	{
		// <dadjoke> Node is Batman </dadjoke>
		ErrorMsgReturn(!parent, "Node has no parent", vec3());

		return wPos - parent->getWorldPos();
	}

	vec3 Node::getRotation(void)
	{
		return (mRot) ? *mScale : vec3(0, 0, 0);
	}

	vec3 Node::getScale(void)
	{
		return (mScale) ? *mScale : vec3(1, 1, 1);
	}
} // namespace GeorgeLib